home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Libraries / VideoToolbox 94.11.17 / VideoToolboxSources / ReadMATLABFile.c < prev    next >
Encoding:
Text File  |  1994-11-17  |  12.0 KB  |  414 lines  |  [TEXT/KAHL]

  1. /*
  2. ReadMATLABFile.c - load/save a matrix from/to a MATLAB data file.
  3. These functions allow any C program to read and write MATLAB data files.
  4.  
  5. int SaveMatDoubles(FILE *f,char *name,long rows,long cols
  6.     ,double *real,double *imag);            // write doubles as 8-byte DOUBLES
  7. int SaveMatShorts(FILE *f,char *name,long rows,long cols
  8.     ,short *real,short *imag);                // write shorts as shorts
  9. int LoadNextMatIntoDoubles(FILE *f,char *name,long *rows,long *cols
  10.     ,double **real,double **imag);            // read 8-byte DOUBLES into doubles
  11. int LoadNextMatIntoShorts(FILE *f,char *name,long *rows,long *cols
  12.     ,short **real,short **imag);            // read 8-byte DOUBLES into shorts
  13. int LoadNamedMatIntoDoubles(FILE *f,char *name,long *rows,long *cols
  14.     ,double **real,double **imag);            // read 8-byte DOUBLES into doubles
  15. int LoadNamedMatIntoShorts(FILE *f,char *name,long *rows,long *cols
  16.     ,short **real,short **imag);            // read 8-byte DOUBLES into shorts
  17.  
  18. All the routines assume an open file, and return an error if they hit end of
  19. file. The SaveXXX routines append a matrix to the existing file. The LoadNextXXX
  20. routines read the next matrix from the file, advancing the file pointer.
  21. SaveXXX and LoadNextXXX can be called repeatedly until they fail (e.g. end of
  22. file is reached). The LoadNamedXXX routines first rewind the file and then scan
  23. it until they find a matrix whose name matches that supplied, or end of file is
  24. reached. The file pointer is left at the end of that matrix. Calling LoadNameXXX
  25. repeatedly will read the same matrix every time: the first instance of the named
  26. matrix.
  27.  
  28. The LoadXXX and SaveXXX routines return 0 if successful and a positive nonzero
  29. integer if they fail.  The two array pointers will be NULL after calling LoadXXX
  30. unless they are loaded. The second (imaginary) pointer will be NULL unless the
  31. matrix was complex. Similarly, when you call SaveXXX you indicate a real matrix
  32. by supplying a NULL second pointer.
  33.  
  34. There is a slight asymmetry here that you should be aware of. SaveMatShorts()
  35. produces a (compact) MATLAB file made up of shorts, but the
  36. LoadXXXMatIntoShorts() will only read a (big) MATLAB file made up of 8-byte
  37. doubles. So you won't always be able to read from C the file you wrote from C.
  38. The reason for this is that while the MATLAB "Load" command supports all the
  39. MATLAB file formats, the MATLAB "Save" command has no provision for specifying
  40. (binary) file formats and thus always uses format type 0, 8-byte short doubles,
  41. so I didn't bother to implement any routines to read any other format. (It would
  42. be easy to add this capability, if it were needed.)
  43.  
  44. EXAMPLES:
  45. This example loads the first two matrices from a MATLAB file:
  46.  
  47.     FILE *f;
  48.     char name[64];
  49.     long rows,cols;
  50.     double *xr,*xi;
  51.     short *mr,*mi;
  52.     int error;
  53.     f = fopen("foo.mat","rb");
  54.     error=LoadNextMatIntoDoubles(f,name,&rows,&cols,&xr,&xi);
  55.      error=LoadNextMatIntoShorts(f,name,&rows,&cols,&mr,&mi);
  56.     fclose(f);
  57.     free(xr);
  58.     free(xi);
  59.     free(mr);
  60.     free(mi);
  61.  
  62. Alternatively, you can read a specific matrix, by name, from the file:
  63.  
  64.     error=LoadNamedMatIntoDoubles(f,"Put name here",&rows,&cols,&xr,&xi);
  65.      error=LoadNamedMatIntoShorts(f,"Put name here",&rows,&cols,&mr,&mi);
  66.  
  67. This example creates a MATLAB file containing four matrices:
  68.  
  69.     FILE *fp;
  70.     double xyz[1000],ar[1000],ai[1000];
  71.     short m[100],n[100];
  72.     fp = fopen("bar.mat","wb");
  73.     SetFileInfo("bar.mat",'MATW','MATL');
  74.     error=SaveMatDoubles(fp,"xyz",2,3,xyz,NULL);    // real
  75.     error=SaveMatShorts(fp,"m",2,3,m,NULL);            // real
  76.     error=SaveMatDoubles(fp,"a",5,5,ar,ai);            // complex
  77.     error=SaveMatShorts(fp,"mc",2,3,m,n);            // complex
  78.     fclose(fp);
  79.  
  80.  
  81. HISTORY:
  82. 11-3-86 J.N. Little wrote loadmat.c and savemat.c
  83.  
  84. [14-Feb-91] jmb -- Added support for MPW C 3.x and THINK C.
  85.  
  86. 1/4/93    dgp Renamed to MatLab.c. DOUBLE is now used soley within the new
  87. WriteXXX and ReadXXX subroutines. C users now only deal with double and short
  88. arrays; necessary conversions are done behind the scenes. double is faster and
  89. more convenient for Macintosh programming than the 8-byte short double used in
  90. the MATLAB files. Added support for file format 3: signed short ints. Omitted
  91. the imagf flag since it's redundant. Omitted the type argument by supplying
  92. several user-callable front ends, each tailored to a particular number type.
  93.  
  94. 2/93 dgp Renamed to ReadMatLabFile.c
  95.  
  96. 6/22-25/93 jas & dgp wrote LoadNamedMat. Renamed LoadMatShorts and
  97. LoadMatDoubles to LoadNextMatIntoShorts and LoadNextMatIntoDoubles. Added
  98. LoadNamedMatIntoShorts and LoadNamedMatIntoDoubles.
  99.  
  100. 12/93 dgp Renamed to ReadMATLABFile.c
  101.  
  102. 7/28/94 dgp added support for Metrowerks CodeWarrior C compiler.
  103. */
  104. #include "VideoToolbox.h"
  105. #include <assert.h>
  106.  
  107. double *ReadDoubles(FILE *f,long elements,char *name);
  108. short *ReadDoublesIntoShorts(FILE *f,long elements,char *name);
  109. int WriteDoubles(FILE *f,long elements,char *name,double *d);
  110. int WriteShorts(FILE *f,long elements,char *name,short *d);
  111. int SaveMat(FILE *f,char *name,long rows,long cols,void *real,void *imag,long type);
  112. int LoadNamedMat(FILE *f,const char *name,long *rows,long *cols
  113.     ,void **real,void **imag,long *fileType,long desiredNumberType);
  114. int LoadNextMat(FILE *f,char *name,long *rows,long *cols
  115.     ,void **real,void **imag,long *fileType,long desiredNumberType);
  116.  
  117. typedef struct {
  118.      long type;        /* type */
  119.      long rows;        /* row dimension */
  120.      long cols;        /* column dimension */
  121.      long imagf;    /* flag indicating imag part */
  122.      long namlen;    /* name length (including NULL) */
  123. } Fmatrix;
  124.  
  125. /* From cmex.h */
  126. // MATLAB files with number format 0 use 8-byte floating point numbers, which
  127. // we'll call DOUBLE.
  128. #undef DOUBLE
  129. #if !defined(__powerc) && (defined(THINK_C) || defined(THINK_CPLUS) || defined(__MWERKS__))
  130.     #define DOUBLE short double
  131. #else
  132.     #define DOUBLE double
  133. #endif
  134.  
  135. int LoadNextMatIntoDoubles(FILE *f,char *name,long *rows,long *cols
  136.     ,double **real,double **imag)
  137. {
  138.     long fileType,desiredNumberType=0;
  139.     
  140.     return LoadNextMat(f,name,rows,cols,(void **)real,(void **)imag
  141.         ,&fileType,desiredNumberType);
  142. }
  143.     
  144. int LoadNextMatIntoShorts(FILE *f,char *name,long *rows,long *cols
  145.     ,short **real,short **imag)
  146. {
  147.     long fileType,desiredNumberType=3;
  148.     
  149.     return LoadNextMat(f,name,rows,cols,(void **)real,(void **)imag
  150.         ,&fileType,desiredNumberType);
  151. }
  152.  
  153. int LoadNamedMatIntoDoubles(FILE *f,const char *name,long *rows,long *cols
  154.     ,double **real,double **imag)
  155. {
  156.     long fileType,desiredNumberType=0;
  157.     
  158.     return LoadNamedMat(f,name,rows,cols,(void **)real,(void **)imag
  159.         ,&fileType,desiredNumberType);
  160. }
  161.     
  162. int LoadNamedMatIntoShorts(FILE *f,const char *name,long *rows,long *cols
  163.     ,short **real,short **imag)
  164. {
  165.     long fileType,desiredNumberType=3;
  166.     
  167.     return LoadNamedMat(f,name,rows,cols,(void **)real,(void **)imag
  168.         ,&fileType,desiredNumberType);
  169. }
  170.  
  171. int SaveMatDoubles(FILE *f,char *name,long rows,long cols,double *real,double *imag)
  172. {
  173.     return SaveMat(f,name,rows,cols,real,imag,0);
  174. }
  175.  
  176. int SaveMatShorts(FILE *f,char *name,long rows,long cols,short *real,short *imag)
  177. {
  178.     return SaveMat(f,name,rows,cols,real,imag,30);
  179. }
  180.     
  181. int LoadNamedMat(FILE *f,const char *name,long *rows,long *cols
  182.     ,void **real,void **imag,long *fileType,long desiredNumberType)
  183. {
  184.     char curname[100];
  185.     int error;
  186.     
  187.     rewind(f);
  188.     while(1){
  189.         error=LoadNextMat(f,curname,rows,cols,real,imag,fileType,desiredNumberType);
  190.         if(error)return error;
  191.         if(strcmp(curname,name)==0)break;
  192.         if(*real!=NULL){
  193.             free(*real);
  194.             *real=NULL;
  195.         }
  196.         if(*imag!=NULL){
  197.             free(*imag);
  198.             *imag=NULL;
  199.         }
  200.     }
  201.     return 0;
  202. }
  203.  
  204. int LoadNextMat(FILE *f,char *name,long *rows,long *cols
  205.     ,void **real,void **imag,long *fileType,long desiredNumberType)
  206. {
  207.     Fmatrix    x;
  208.     long elements,namlen,numberFormat;
  209.     
  210.     *real=*imag=NULL;
  211.     name[0]=0;
  212.     if(feof(f))return 1;
  213.  
  214.     // Get Fmatrix structure from file
  215.     if (fread((char *)&x,sizeof(Fmatrix),1,f) != 1) return 2;
  216.     *fileType = x.type;
  217.     *rows = x.rows;
  218.     *cols = x.cols;
  219.     namlen = x.namlen;
  220.     elements = x.rows * x.cols;
  221.  
  222.     if(x.type/1000!=1)return 3;        // not Macintosh-compatible binary format
  223.     if(x.type/100%10!=0)return 4;    // transposed
  224.     numberFormat=x.type/10%10;
  225.     if(numberFormat!=0)return 5;    // not 8-byte doubles
  226.  
  227.     // Get matrix name from file
  228.     if (fread(name,sizeof(char),namlen,f) != namlen) return 6;
  229.     
  230.     // Get Real part of matrix from file
  231.     switch(desiredNumberType){
  232.     case 0:
  233.         *real=ReadDoubles(f,elements,name);
  234.         break;
  235.     case 3:
  236.         *real=ReadDoublesIntoShorts(f,elements,name);
  237.         break;
  238.     default:
  239.         *real=NULL;
  240.     }
  241.     if(*real==NULL)return 7;
  242.  
  243.     // Get Imag part of matrix from file, if it exists
  244.     if (x.imagf) {
  245.         switch(desiredNumberType){
  246.         case 0:
  247.             *imag=ReadDoubles(f,elements,name);
  248.             break;
  249.         case 3:
  250.             *imag=ReadDoublesIntoShorts(f,elements,name);
  251.             break;
  252.         }
  253.         if(*imag==NULL){
  254.             free(*real);
  255.             *real=NULL;
  256.             return 8;
  257.         }
  258.     }
  259.     return 0;
  260. }
  261.  
  262. int SaveMat(FILE *f,char *name,long rows,long cols,void *real,void *imag,long type)
  263. {
  264.     Fmatrix    x;
  265.     long elements;
  266.     int error;
  267.     int fileFormat;
  268.     
  269.     type%=100;    // not transposed
  270.     type+=1000;    // indicate Macintosh-compatible binary format
  271.     x.type = type;
  272.     x.rows = rows;
  273.     x.cols = cols;
  274.     if(imag==NULL)x.imagf=0;
  275.     else x.imagf=1;
  276.     x.namlen = strlen(name) + 1;
  277.     elements = x.rows * x.cols;
  278.  
  279.     if(x.type/1000!=1)return 9;        // not Macintosh-compatible binary format
  280.     if(x.type/100%10!=0)return 10;    // transposed
  281.     fileFormat=x.type/10%10;
  282.     if(fileFormat!=0 && fileFormat!=3)return 11; // neither 8-byte double, nor short
  283.  
  284.     fwrite(&x,sizeof(Fmatrix),1,f);
  285.     fwrite(name,sizeof(char),(long)x.namlen,f);
  286.     switch(fileFormat){
  287.     case 0:
  288.         error=WriteDoubles(f,elements,name,real);
  289.         break;
  290.     case 3:
  291.         error=WriteShorts(f,elements,name,real);
  292.         break;
  293.     default:
  294.         error=1;
  295.     }
  296.     if(error)return 12;
  297.     if (imag!=NULL) {
  298.         switch(fileFormat){
  299.         case 0:
  300.             error=WriteDoubles(f,elements,name,imag);
  301.             break;
  302.         case 3:
  303.             error=WriteShorts(f,elements,name,imag);
  304.             break;
  305.         default:
  306.             error=1;
  307.         }
  308.         if(error)return 13;
  309.     }
  310.     return 0;
  311. }
  312.  
  313. // Reads DOUBLES (8-byte short doubles) into doubles
  314. double *ReadDoubles(FILE *f,long elements,char *name)
  315. {
  316.     DOUBLE *D;
  317.     double *d;
  318.     long i,n,j;
  319.     const dSize=2048/sizeof(DOUBLE);    // Can be whatever you want. Bigger is faster.
  320.     
  321.     assert(sizeof(DOUBLE)==8);
  322.     D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
  323.     if(D==NULL){
  324.         printf("\nError: not enough room for buffer\n");
  325.         return NULL;
  326.     }
  327.     if (!(d = (double *)malloc(elements*sizeof(*d)))) {
  328.         printf("\nError: Variable %s too big to load\n",name);
  329.         return NULL;
  330.     }
  331.     for(i=0;i<elements;){
  332.         if(dSize<elements-i)n=dSize;
  333.         else n=elements-i;
  334.         if(fread(D,sizeof(DOUBLE),n,f) != n) {
  335.             free(d);
  336.             free(D);
  337.             return NULL;
  338.         }
  339.         for(j=0;j<n;j++)d[i++]=D[j];    // convert DOUBLE to double
  340.     }
  341.     free(D);
  342.     return d;
  343. }
  344.  
  345. // Reads DOUBLES (8-byte short doubles) into shorts
  346. short *ReadDoublesIntoShorts(FILE *f,long elements,char *name)
  347. {
  348.     DOUBLE *D;
  349.     short *d;
  350.     long i,n,j;
  351.     const dSize=2048/sizeof(DOUBLE);    // Can be whatever you want. Bigger is faster.
  352.     
  353.     assert(sizeof(DOUBLE)==8);
  354.     D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
  355.     if(D==NULL){
  356.         printf("\nError: not enough room for buffer\n");
  357.         return NULL;
  358.     }
  359.     if (!(d = (short *)malloc(elements*sizeof(*d)))) {
  360.         printf("\nError: Variable %s too big to load\n",name);
  361.         return NULL;
  362.     }
  363.     for(i=0;i<elements;){
  364.         if(dSize<elements-i)n=dSize;
  365.         else n=elements-i;
  366.         if(fread(D,sizeof(DOUBLE),n,f) != n) {
  367.             free(d);
  368.             free(D);
  369.             return NULL;
  370.         }
  371.         for(j=0;j<n;j++)d[i++]=D[j];    // convert DOUBLE to short
  372.     }
  373.     free(D);
  374.     return d;
  375. }
  376.  
  377. // Writes doubles as DOUBLES (8-byte short doubles)
  378. int WriteDoubles(FILE *f,long elements,char *name,double *d)
  379. {
  380.     DOUBLE *D;
  381.     long i,n,j;
  382.     const dSize=2048/sizeof(DOUBLE);    // Can be whatever you want. Bigger is faster.
  383.     
  384.     name;    // prevent "unused argument" warning
  385.     assert(sizeof(DOUBLE)==8);
  386.     if (d==NULL) return 14;
  387.     D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
  388.     if(D==NULL){
  389.         printf("\nError: not enough room for buffer\n");
  390.         return 15;
  391.     }
  392.     for(i=0;i<elements;){
  393.         if(dSize<elements-i)n=dSize;
  394.         else n=elements-i;
  395.         for(j=0;j<n;j++)D[j]=d[i++];    // convert double to DOUBLE
  396.         if(fwrite(D,sizeof(DOUBLE),n,f) != n) {
  397.             free(D);
  398.             return 16;
  399.         }
  400.     }
  401.     free(D);
  402.     return 0;
  403. }
  404.  
  405. // Writes shorts as shorts
  406. int WriteShorts(FILE *f,long elements,char *name,short *d)
  407. {
  408.     name;    // prevent "unused argument" warning
  409.     assert(sizeof(short)==2);
  410.     if (d==NULL) return 17;
  411.     if(fwrite(d,sizeof(short),elements,f) != elements) return 18;
  412.     return 0;
  413. }
  414.